# -*-coding:utf-8-*-

from tornado.gen import coroutine, Return
from delegates.base import BaseDelegate
from delegates.hfs.dgk.dgk_products_delegate import DgkProduct
from delegates.hfs.dgk.dgk_users_delegate import DgkUser
import time
import datetime
from daos.base_async import BaseRecord

SPECIFICS = {
    'vid': 'VENDOR_ID',
    'did': 'DEALER_ID',  # 经销商
    'sid': 'SPREADER_ID',  # 推广者
    'ssid': 'SUPERIOR_SPREADER_ID',  # 上级推广者
    'tsid': 'TOP_SPREADER_ID',  # 顶级推广者

    'spread_bonus_points': 100,
    'spread_total_price': 100,
    'bonus_points': 100,
    'total_price': 100,

    'commission_s': 15,
    'commission_ss': 9,
    'commission_ts': 6,
    'commission': 15,  # for spreader
}


class DgkOrder(BaseRecord):
    pass


class DgkOrdersDelegate(BaseDelegate):
    def __init__(self, *args, **kwargs):
        super(DgkOrdersDelegate, self).__init__(*args, **kwargs)
        self.return_expire_seconds = int(datetime.timedelta(days=7).total_seconds())
        self.commission_transfer_delay_seconds = int(datetime.timedelta(days=15).total_seconds())
        self.status_vendor = ['delivering', 'delivered', 'notify_return', 'refuse', 'returned']
        self.status_user = ['to_be_paid', 'paid', 'done', 'apply_return', 'returning']
        self.commission_s = 0.0
        self.commission_ss = 0.0
        self.commission_ts = 0.0

    @coroutine
    def on_pre_create(self, **kwargs):
        bonus_points = 0.0
        spread_bonus_points = 0.0
        spread_total_price = 0.0
        commission_s = 0.0
        commission_ss = 0.0
        commission_ts = 0.0

        products = kwargs['products']
        for product in products:
            total_price = product['unit_price'] * product['quantity']
            product_specifics = yield self._get_product_specifics(product['product_id'])
            if not product_specifics:
                self._respond_error(1, 'invalid product')
            p = DgkProduct(product_specifics)
            if p.bonus_points_unit is not None and p.bonus_points_multiple is not None:
                bp = total_price / p.bonus_points_unit * p.bonus_points_multiple
                bonus_points += bp
                if p.increase_spread_bonus_points is not None and p.increase_spread_bonus_points:
                    spread_bonus_points += bp
                    spread_total_price += total_price
            if p.percentages is not None:
                commission_s += total_price * p.percentages[0] / 100
                commission_ss += total_price * p.percentages[1] / 100
                commission_ts += total_price * p.percentages[2] / 100
        specifics = {
            'commission_s': commission_s,
            'commission_ss': commission_ss,
            'commission_ts': commission_ts,
            'bonus_points': bonus_points,
            'spread_bonus_points': spread_bonus_points,
            'spread_total_price': spread_total_price,
            'total_price': kwargs['total_price'],
        }
        user_specifics = yield self._get_user_specifics()
        user = DgkUser(user_specifics)
        specifics['vid'] = user.vendor_id
        specifics['sid'] = user.spreader_id
        specifics['ssid'] = user.superior_spreader_id
        specifics['tsid'] = user.top_spreader_id
        specifics['uid'] = self._uid
        specifics['cur_status'] = 'to_be_paid'
        raise Return(specifics)

    @coroutine
    def get_order_list_for_commission(self, **kwargs):
        uid = self._uid
        level = int(kwargs['level']) if 'level' in kwargs else 0
        if 0 == level:
            filter_cond = {
                '$or': [
                    {'specifics.sid': uid},
                    {'specifics.ssid': uid},
                    {'specifics.tsid': uid}
                ]}
        elif 1 == level:
            filter_cond = {'specifics.sid': uid}
        elif 2 == level:
            filter_cond = {'specifics.ssid': uid}
        elif 3 == level:
            filter_cond = {'specifics.tsid': uid}
        else:
            raise Exception('invalid level: %d' % level)
        # 只有已完成的订单才参与提成计算
        filter_cond.update(status='done')
        raise Return((filter_cond, None))

    def get_order_list(self, **kwargs):
        filter_cond = {
            '$or': [
                {'uid': self._uid},
                {'specifics.vid': self._uid},
            ]}
        # projection = {'uid': 0, 'vid': 0, 'did': 0}
        # projection.update(dict([(x, 0) for x in self.spread_fields]))
        if 'status' in kwargs:
            filter_cond.update(status=kwargs.pop('status'))
        if 'type' in kwargs:
            filter_cond.update(type=kwargs.pop('type'))
        return filter_cond, None

    @coroutine
    def on_pre_get_list(self, **kwargs):
        if 'aspect' in kwargs and 'commission' == kwargs['aspect']:
            result = yield self.get_order_list_for_commission(**kwargs)
        else:
            result = self.get_order_list(**kwargs)
        raise Return(result)

    def on_per_list_item(self, item, **kwargs):
        if 'aspect' not in kwargs or 'commission' != kwargs['aspect']:
            return True
        uid = self._uid
        a = item['specifics']
        if a['sid'] == uid:
            if 'commission_s' in a:
                # a['commission'] = a['commission_s']
                a['level'] = 1
        elif a['ssid'] == uid:
            if 'commission_ss' in a:
                # a['commission'] = a['commission_ss']
                a['level'] = 2
        elif a['tsid'] == uid:
            if 'commission_ts' in a:
                # a['commission'] = a['commission_ts']
                a['level'] = 3
        return 'level' in a

    @coroutine
    def on_pre_traverse(self, **kwargs):
        self.commission_s = 0.0
        self.commission_ss = 0.0
        self.commission_ts = 0.0
        filter_cond = {
            '$or': [
                {'specifics.sid': self._uid},
                {'specifics.ssid': self._uid},
                {'specifics.tsid': self._uid}
            ],
            'status': 'done',
        }
        raise Return((filter_cond, None))

    def on_traversing_item(self, item, **kwargs):
        a = item['specifics']
        if a['sid'] == self._uid:
            if 'commission_s' in a:
                self.commission_s += a['commission_s']
        elif a['ssid'] == self._uid:
            if 'commission_ss' in a:
                self.commission_ss += a['commission_ss']
        elif a['tsid'] == self._uid:
            if 'commission_ts' in a:
                self.commission_ts += a['commission_ts']
        return True

    def on_post_traverse(self, **kwargs):
        return {
            'commission_as_s': self.commission_s,
            'commission_as_ss': self.commission_ss,
            'commission_as_ts': self.commission_ts,
        }

    def on_pre_get_statistics(self, **kwargs):
        if 'aspect' not in kwargs or 'commissions' != kwargs['aspect']:
            self._respond_error(1, 'unsupported aspect')
        pipeline = [
            {
                '$match': {
                    '$or': [
                        {'specifics.sid': self._uid},
                        {'specifics.ssid': self._uid},
                        {'specifics.tsid': self._uid},
                    ]
                }
            },
            {
                '$project': {
                    '_id': 1,
                    'commission_as_s': {
                        '$cond': [{'$eq': ['$specifics.sid', self._uid]}, '$specifics.commission_s', 0],
                    },
                    'commission_as_ss': {
                        '$cond': [{'$eq': ['$specifics.ssid', self._uid]}, '$specifics.commission_ss', 0],
                    },
                    'commission_as_ts': {
                        '$cond': [{'$eq': ['$specifics.tsid', self._uid]}, '$specifics.commission_ts', 0],
                    },
                }
            },
            {
                '$group': {
                    '_id': 0,
                    'commission_as_s': {'$sum': '$commission_as_s'},
                    'commission_as_ss': {'$sum': '$commission_as_ss'},
                    'commission_as_ts': {'$sum': '$commission_as_ts'},
                }
            },
        ]
        default = {
            'commission_as_s': 0,
            'commission_as_ss': 0,
            'commission_as_ts': 0,
        }
        return pipeline, default

    def on_pre_get(self, **kwargs):
        projection = {'_id': 0}
        filter_cond = {'$or': [
            {'uid': self._uid},
            {'specifics.vid': self._uid},
        ]}
        return filter_cond, projection

    @coroutine
    def _on_update_order_status(self, order, status):
        # vendor 和 normal user 可以修改的状态不一样
        if self._uid == order.vid:
            if status not in self.status_vendor:
                self._respond_error(1, 'invalid status(%s)for vendor, cur_status: %s ' % (status, order.cur_status))
        elif self._uid == order.uid:
            if status not in self.status_user:
                self._respond_error(2, 'invalid status(%s)for user, cur_status: %s ' % (status, order.cur_status))
        else:
            self._respond_error(3, 'invalid user')
        # 后续业务需要,将新旧两状态存于 specifics 中
        modification = {'cur_status': status, 'old_status': order.cur_status}
        raise Return(modification)

    @coroutine
    def on_pre_update(self, **kwargs):
        oid = kwargs['oid']
        modification = kwargs['modification']

        order_specifics = yield self._get_order_specifics(oid)
        order = DgkOrder(order_specifics)

        if 'status' in modification:
            status = modification['status']
            modification = yield self._on_update_order_status(order, status)
            order_specifics.update(modification)

        raise Return(order_specifics)

    @coroutine
    def _update_consumptions_and_commissions(self, order):
        consumptions = {
            'consumptions.bonus_points': order.bonus_points,
            'consumptions.spread_bonus_points': order.spread_bonus_points,
            'consumptions.amount': order.total_price,
            'consumptions.spread_amount': order.spread_total_price,
        }
        yield self._update_user_specifics(self._uid, {'$inc': consumptions})
        if order.sid is not None:
            yield self._update_user_specifics(order.sid, {'$inc': {'commissions.as_spreader': order.commission_s}})
        if order.ssid is not None:
            yield self._update_user_specifics(order.ssid, {'$inc': {'commissions.as_superior_spreader': order.commission_ss}})
        if order.tsid is not None:
            yield self._update_user_specifics(order.tsid, {'$inc': {'commissions.as_top_spreader': order.commission_ts}})

    @coroutine
    def on_post_update(self, **kwargs):
        oid = kwargs['oid']

        order_specifics = yield self._get_order_specifics(oid)
        order = DgkOrder(order_specifics)

        if order.cur_status == order.old_status:
            raise Return()

        if 'done' == order.cur_status:
            yield self._update_consumptions_and_commissions(order)

